home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 23 / AACD 23.iso / AACD / Programming / tek / examples / balls.c < prev    next >
C/C++ Source or Header  |  2001-05-25  |  22KB  |  974 lines

  1.  
  2. /*
  3. **    tek/examples/balls.c
  4. **    networked balls demo
  5. **
  6. **    - use the right mouse button to create/destroy balls
  7. **    (which are actually rectangles, but who cares :)
  8. **
  9. **    - start another client, preferrably on another machine,
  10. **    and contact to either the left or right window border:
  11. **
  12. **    balls left <host-IP> <portnumber-right>    contacts the right window border
  13. **    balls right <host-IP> <portnumber-left>    contacts the left window border
  14. **
  15. */
  16.  
  17. #include <math.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20.  
  21. #include <tek/debug.h>
  22. #include <tek/visual.h>
  23. #include <tek/sock.h>
  24. #include <tek/array.h>
  25.  
  26. /******************************************************************** 
  27. **    structs, constants
  28. ********************************************************************/
  29.  
  30. #define LEFT            -1
  31. #define RIGHT            1
  32.  
  33. #define MSG_WELCOME        1
  34. #define MSG_MIGRATE        2
  35.  
  36. #define MOUSEACCEL                3.5
  37. #define MOUSEFRICTION            0.4
  38.  
  39. #define BALLUPDATEPERSECOND        50
  40. #define WORLDUPDATEPERSECOND    50
  41.  
  42. #define BALLGRAV                0.002
  43. #define BALLFRICTION            0.9985
  44. #define BALLRADIUS                0.06
  45.  
  46. enum PENS {    PBLACK, PBLUE, PRED, PGREEN, PWHITE, PGREY, NUMPENS };
  47.  
  48. struct world
  49. {
  50.     THNDL handle;                        /* object handle */
  51.     TAPTR task;                            /* world maintenance task */
  52.     TVISUAL *visual;                    /* visual object */
  53.     TVPEN *pentab;                        /* pentable */
  54.     TLIST activeballs;                    /* list of active balls */
  55.     TLIST cachedballs;                    /* list of cached balls */
  56.  
  57.     TLOCK lock;                            /* child locking */
  58.     TINT width, height;                    /* world window width/height */
  59.  
  60.     TPORT *leftout, *rightout;            /* world portals to outside */
  61.  
  62.     TPORT *leftin, *rightin;            /* world portals to inside */
  63.     TINT leftport, rightport;            /* world portals to inside - port numbers */
  64.     
  65.     TINT contact;                        /* contact to left/right */
  66.     TSTRPTR host;                        /* contact to IP number */
  67.     TUINT port;                            /* contact port number */
  68. };
  69.  
  70.  
  71. /******************************************************************** 
  72. **    ball
  73. ********************************************************************/
  74.  
  75. #define BALLSIG_WAKE            0x80000000
  76. #define BALLSIG_SLEEP            0x40000000
  77. #define BALLSIG_DRAW            0x20000000
  78.  
  79.  
  80. struct ball
  81. {
  82.     THNDL handle;            /* object handle */
  83.     struct world *world;    /* this ball's world */
  84.     TVISUAL *parentvisual;    /* parent visual object being attached to */
  85.     TVISUAL *visual;        /* client to the parent visual object */
  86.     TVPEN backpen, pen;        /* background and ball pen */
  87.     TAPTR task;                /* ball maintenance task */
  88.     TLOCK lock;                /* lock for this entity */
  89.     TFLOAT x,y;                /* position */
  90.     TFLOAT vx,vy;            /* motion vector */
  91.     TFLOAT gravity;            /* current gravity factor */
  92.     TFLOAT radius;            /* ball's radius (fraction to visual) */
  93. };
  94.  
  95. TINT destroyball(struct ball *b);
  96. TBOOL ballinitfunc(TAPTR task);
  97. TVOID ballfunc(TAPTR task);
  98. TBOOL ballupdate(struct ball *b, TFLOAT f);
  99.  
  100. struct ball *createball(TAPTR parenttask, struct world *world, TVISUAL *visual, TVPEN backpen, TVPEN pen, TFLOAT x, TFLOAT y, TFLOAT vx, TFLOAT vy)
  101. {
  102.     struct ball *b = TTaskAllocHandle0(parenttask, destroyball, sizeof(struct ball));
  103.     if (b)
  104.     {
  105.         TTAGITEM tasktags[3];
  106.  
  107.         tasktags[0].tag = TTask_InitFunc;
  108.         tasktags[0].value = (TTAG) ballinitfunc;
  109.         tasktags[1].tag = TTask_UserData;
  110.         tasktags[1].value = (TTAG) b;
  111.         tasktags[2].tag = TTAG_DONE;
  112.         
  113.         b->world = world;
  114.         b->parentvisual = visual;
  115.         b->backpen = backpen;
  116.         b->pen = pen;
  117.         b->x = x;
  118.         b->y = y;
  119.         b->vx = vx;
  120.         b->vy = vy;
  121.         b->gravity = BALLGRAV;
  122.         b->radius = BALLRADIUS;
  123.  
  124.         b->task = TCreateTask(parenttask, ballfunc, tasktags);
  125.         if (b->task)
  126.         {
  127.             return b;
  128.         }
  129.  
  130.         TDestroy(b);
  131.     }
  132.     return TNULL;
  133. }
  134.  
  135. TINT destroyball(struct ball *b)
  136. {
  137.     TSignal(b->task, TTASK_SIG_ABORT);
  138.     TDestroy(b->task);
  139.     TMMUFreeHandle(b);
  140.     return 0;
  141. }
  142.  
  143. TBOOL ballinitfunc(TAPTR task)
  144. {
  145.     struct ball *b = TTaskGetData(task);
  146.     if (TAllocSignal(task, BALLSIG_WAKE | BALLSIG_SLEEP | BALLSIG_DRAW))
  147.     {
  148.         if (TInitLock(task, &b->lock, TNULL))
  149.         {
  150.             b->visual = TAttachVisual(task, b->parentvisual, TNULL);
  151.             if (b->visual)
  152.             {
  153.                 return TTRUE;
  154.             }
  155.             TDestroy(&b->lock);
  156.         }
  157.     }
  158.     return TFALSE;
  159. }
  160.  
  161.  
  162. TVOID ballfunc(TAPTR task)
  163. {
  164.     struct ball *b = TTaskGetData(task);
  165.     TUINT signals;
  166.     TTIME delay, lasttime, now;
  167.     TBOOL awake = TFALSE;
  168.     TINT ox = -1, oy = 0, ow = 0, oh = 0;
  169.     TFLOAT f = 1.0;
  170.  
  171.     TFTOTIME(1.0f/BALLUPDATEPERSECOND, &delay);
  172.  
  173.     TTimeQuery(task, &lasttime);
  174.  
  175.     do
  176.     {
  177.         signals = TTimedWait(task, 
  178.             TTASK_SIG_ABORT | BALLSIG_WAKE | BALLSIG_SLEEP | BALLSIG_DRAW, &delay);
  179.  
  180.         TTimeQuery(task, &now);
  181.         f = (TTIMETOF(&now) - TTIMETOF(&lasttime)) * BALLUPDATEPERSECOND;
  182.         lasttime = now;
  183.  
  184.         if (signals & BALLSIG_WAKE)
  185.         {
  186.             awake = TTRUE;
  187.         }
  188.  
  189.         if (signals & BALLSIG_SLEEP)
  190.         {
  191.             if (ox >= 0)
  192.             {
  193.                 TVFRect(b->visual, ox, oy, ow, oh, b->backpen);
  194.                 TVSync(b->visual);
  195.                 ox = -1;
  196.             }
  197.             awake = TFALSE;
  198.         }
  199.  
  200.         if (awake)
  201.         {    
  202.             if (signals & BALLSIG_DRAW)
  203.             {
  204.                 TINT width = 600, height = 400;
  205.                 TINT nw, nh, nx, ny;
  206.     
  207.                 TLock(&b->lock);
  208.     
  209.                 nw = b->radius * 2 * width;
  210.                 nh = b->radius * 2 * height;
  211.                 nx = (b->x - b->radius) * width;
  212.                 ny = b->y * (height - nh);
  213.     
  214.                 if (nx < 0)
  215.                 {
  216.                     nw += nx;
  217.                     nx = 0;
  218.                 }
  219.                 else if (nx + nw > width)
  220.                 {
  221.                     nw += width - (nx + nw);
  222.                 }
  223.     
  224.                 if (ox >= 0)
  225.                 {
  226.                     TVFRect(b->visual, ox, oy, ow, oh, b->backpen);
  227.                     ox = -1;
  228.                 }
  229.                 if (b->y >= 0)
  230.                 {
  231.                     TVFRect(b->visual, nx, ny, nw, nh, b->pen);
  232.                     ox = nx; oy = ny; ow = nw; oh = nh;
  233.                 }
  234.  
  235.                 TVSync(b->visual);
  236.                     
  237.                 TUnlock(&b->lock);
  238.             }
  239.  
  240.             awake = ballupdate(b, f);
  241.         }
  242.  
  243.     } while (!(signals & TTASK_SIG_ABORT));
  244.  
  245.     TDestroy(b->visual);
  246.     TDestroy(&b->lock);
  247. }
  248.  
  249.  
  250. TBOOL ballmigrate(struct ball *b, TINT direction)
  251. {
  252.     TUINT *msg = TTaskAllocMsg(b->task, 32);
  253.     if (msg)
  254.     {
  255.         TFLOAT newx = direction == LEFT ? b->x + 1.0f : b->x - 1.0f;
  256.  
  257.         *(msg + 0) = THTON32(MSG_MIGRATE);
  258.         *(msg + 1) = (TUINT) b;
  259.         *(msg + 2) = direction;
  260.         *((TFLOAT *) (msg + 3)) = newx; *(msg + 3) = THTON32(*(msg + 3));
  261.         *((TFLOAT *) (msg + 4)) = b->y; *(msg + 4) = THTON32(*(msg + 4));
  262.         *((TFLOAT *) (msg + 5)) = b->vx; *(msg + 5) = THTON32(*(msg + 5));
  263.         *((TFLOAT *) (msg + 6)) = b->vy; *(msg + 6) = THTON32(*(msg + 6));
  264.         TPutReplyMsg(direction == LEFT ? b->world->leftout : b->world->rightout, TTaskPort(b->world->task), msg);
  265.         TSignal(b->task, BALLSIG_SLEEP);
  266.         return TTRUE;
  267.     }
  268.     return TFALSE;
  269. }
  270.  
  271. TBOOL ballupdate(struct ball *b, TFLOAT f)
  272. {
  273.     TBOOL awake = TTRUE;
  274.     
  275.     TLock(&b->lock);
  276.  
  277.     b->x += b->vx * f;
  278.     b->y += b->vy * f;
  279.  
  280.     if (b->y >= 1.0f)
  281.     {
  282.         b->y += 1.0f - b->y;
  283.         b->vy = -b->vy;
  284.     }
  285.     
  286.  
  287.     TLock(&b->world->lock);
  288.     
  289.     if (b->x >= 1.0f)
  290.     {
  291.         if (b->world->rightout)
  292.         {
  293.             if (ballmigrate(b, RIGHT))
  294.             {
  295.                 awake = TFALSE;
  296.             }
  297.         }
  298.         else
  299.         {
  300.             b->x += 1.0f - b->x;
  301.             b->vx = -b->vx;
  302.         }
  303.     }
  304.  
  305.     if (b->x < 0.0f)
  306.     {
  307.         if (b->world->leftout)
  308.         {
  309.             if (ballmigrate(b, LEFT))
  310.             {
  311.                 awake = TFALSE;
  312.             }
  313.         }
  314.         else
  315.         {
  316.             b->x -= b->x;
  317.             b->vx = -b->vx;
  318.         }
  319.     }
  320.  
  321.     TUnlock(&b->world->lock);
  322.  
  323.     if (awake)
  324.     {
  325.         b->vx *= BALLFRICTION;
  326.         b->vy *= BALLFRICTION;
  327.         b->vy += b->gravity;
  328.         if (TABS(b->vx) < 0.000001f) b->vx = 0.0;
  329.         if (TABS(b->vy) < 0.000001f) b->vx = 0.0;
  330.     }
  331.     
  332.     TUnlock(&b->lock);
  333.  
  334.     return awake;
  335. }
  336.  
  337.  
  338. /******************************************************************** 
  339. **    world
  340. ********************************************************************/
  341.  
  342. TINT destroyworld(struct world *w);
  343. TBOOL worldinitfunc(TAPTR task);
  344. TVOID worldfunc(TAPTR task);
  345. struct ball *newball(struct world *w, TINT mousex, TINT mousey);
  346. TVOID setballpos(struct world *w, struct ball *b, TINT mousex, TINT mousey);
  347. TVOID setballv(struct world *w, struct ball *b, TFLOAT mousevx, TFLOAT mousevy);
  348. struct ball *pickball(struct world *w, TINT mousex, TINT mousey);
  349. TVOID destroyballlist(struct world *w, TLIST *list);
  350. TVOID sigballlist(struct world *w, TLIST *list, TUINT sig);
  351. TBOOL handlenetmsg(struct world *w, TPORT *inport, TPORT **outport);
  352. struct ball *newnetball(struct world *w, TFLOAT x, TFLOAT y, TFLOAT vx, TFLOAT vy);
  353. TVOID handlenetreply(struct world *w);
  354.  
  355. struct world *createworld(TAPTR parenttask, TINT contact, TSTRPTR host, TUINT port)
  356. {
  357.     struct world *w = TTaskAllocHandle0(parenttask, destroyworld, sizeof(struct world));
  358.     if (w)
  359.     {
  360.         TTAGITEM tasktags[3];
  361.  
  362.         tasktags[0].tag = TTask_InitFunc;
  363.         tasktags[0].value = (TTAG) worldinitfunc;
  364.         tasktags[1].tag = TTask_UserData;
  365.         tasktags[1].value = (TTAG) w;
  366.         tasktags[2].tag = TTAG_DONE;
  367.  
  368.         w->contact = contact;
  369.         w->host = host;
  370.         w->port = port;
  371.  
  372.         w->task = TCreateTask(parenttask, worldfunc, tasktags);
  373.         if (w->task)
  374.         {
  375.             return w;
  376.         }
  377.  
  378.         TDestroy(w);
  379.     }
  380.     return TNULL;
  381. }
  382.  
  383. TINT destroyworld(struct world *w)
  384. {
  385.     TDestroy(w->task);
  386.     TMMUFreeHandle(w);
  387.     return 0;
  388. }
  389.  
  390. TBOOL worldinitfunc(TAPTR task)
  391. {
  392.     struct world *w = TTaskGetData(task);
  393.     
  394.     w->leftin = TCreatePort(task, TNULL);
  395.     w->rightin = TCreatePort(task, TNULL);
  396.     if (w->leftin && w->rightin)
  397.     {
  398.         TTAGITEM tags[2];
  399.         TTIME timeout;
  400.         TFTOTIME(1000000, &timeout);
  401.         TInitTags(tags);
  402.         TAddTag(tags, TSock_IdleTimeout, (TTAG) &timeout);
  403.  
  404.         w->leftport = TAddSockPort(w->leftin, 0, tags);
  405.         w->rightport = TAddSockPort(w->rightin, 0, tags);
  406.         if (w->leftport && w->rightport)
  407.         {
  408.             TBOOL success = TTRUE;
  409.             
  410.             if (w->contact)
  411.             {
  412.                 TPORT *contactport = TNULL;
  413.                 TUINT callbackport = 0;
  414.  
  415.                 success = TFALSE;
  416.  
  417.                 TFTOTIME(1.0f, &timeout);
  418.                 TInitTags(tags);
  419.                 TAddTag(tags, TSock_ReplyTimeout, (TTAG) &timeout);
  420.         
  421.                 if (w->contact == LEFT)
  422.                 {
  423.                     contactport = w->leftout = TFindSockPort(task, w->host, w->port, tags);
  424.                     callbackport = w->leftport;
  425.                 }
  426.                 else if (w->contact == RIGHT)
  427.                 {
  428.                     contactport = w->rightout = TFindSockPort(task, w->host, w->port, tags);
  429.                     callbackport = w->rightport;
  430.                 }
  431.  
  432.                 if (contactport)
  433.                 {
  434.                     TBYTE *welcomemsg = TTaskAllocMsg(task, 32);
  435.                     if (welcomemsg)
  436.                     {
  437.                         *((TUINT *) (welcomemsg + 0)) = THTON32(MSG_WELCOME);
  438.                         *((TUINT *) (welcomemsg + 4)) = THTON32(callbackport);
  439.                         TPutReplyMsg(contactport, TTaskPort(task), welcomemsg);
  440.                         TWaitPort(TTaskPort(task));
  441.                         welcomemsg = TGetMsg(TTaskPort(task));
  442.                         success = (TGetMsgStatus(welcomemsg) == TMSG_STATUS_ACKD);
  443.                         TFreeMsg(welcomemsg);
  444.                     }
  445.                 }
  446.             }
  447.             
  448.             if (success)
  449.             {
  450.                 if (TInitLock(task, &w->lock, TNULL))
  451.                 {
  452.                     w->visual = TCreateVisual(task, TNULL);
  453.                     if (w->visual)
  454.                     {
  455.                         w->pentab = TTaskAlloc(task, sizeof(TVPEN) * NUMPENS);
  456.                         if (w->pentab)
  457.                         {
  458.                             w->pentab[PBLACK] = TVAllocPen(w->visual, 0x000000);
  459.                             w->pentab[PRED] = TVAllocPen(w->visual, 0xaa0000);
  460.                             w->pentab[PBLUE] = TVAllocPen(w->visual, 0x2222ff);
  461.                             w->pentab[PGREEN] = TVAllocPen(w->visual, 0x00ff00);
  462.                             w->pentab[PWHITE] = TVAllocPen(w->visual, 0xffffff);
  463.                             w->pentab[PGREY] = TVAllocPen(w->visual, 0x556677);
  464.                             TVSetInput(w->visual, TITYPE_NONE, TITYPE_VISUAL_CLOSE | TITYPE_KEY | TITYPE_MOUSEBUTTON | TITYPE_VISUAL_NEWSIZE);
  465.                             TInitList(&w->activeballs);
  466.                             TInitList(&w->cachedballs);
  467.                             w->width = 600;
  468.                             w->height = 400;
  469.                             return TTRUE;
  470.                         }
  471.                         TDestroy(w->visual);
  472.                     }
  473.                     TDestroy(&w->lock);
  474.                 }
  475.             }
  476.             
  477.             TDestroy(w->leftout);
  478.             TDestroy(w->rightout);
  479.         }
  480.         TDestroy(w->leftin);
  481.         TDestroy(w->rightin);
  482.     }
  483.     return TFALSE;
  484. }
  485.  
  486. TVOID worldfunc(TAPTR task)
  487. {
  488.     struct world *w = TTaskGetData(task);
  489.  
  490.     TINT i;
  491.     TIMSG *imsg;
  492.     TFLOAT f, delayf = 1.0f/WORLDUPDATEPERSECOND;
  493.     TBOOL mousemove;
  494.     TTIME delay, now, lasttime;
  495.     TBOOL abort = TFALSE;
  496.     TINT mousex = 0, mousey = 0, omx = 0, omy = 0;        /* current, old mouse position */
  497.     struct ball *control = TNULL;                        /* ball under mouse, or TNULL */
  498.     TFLOAT mousevx = 0, mousevy = 0;                    /* mouse vector */
  499.     TUINT signals;
  500.  
  501.     TVClear(w->visual, w->pentab[PGREY]);
  502.     TVFRect(w->visual, 0,0,600,400, w->pentab[PBLACK]);
  503.     
  504.     TTimeQuery(task, &lasttime);
  505.     
  506.     TFTOTIME(1.0f/WORLDUPDATEPERSECOND, &delay);
  507.  
  508.     do
  509.     {
  510.         TBOOL newsize = TFALSE;
  511.     
  512.         if (delayf > 0.00001f)
  513.         {
  514.             TFTOTIME(delayf, &delay);
  515.             signals = TTimedWait(task, 
  516.                 w->visual->iport->signal | w->leftin->signal | w->rightin->signal | TTaskPort(task)->signal, &delay);
  517.         }
  518.         else
  519.         {
  520.             signals = TSetSignal(task, 0, w->visual->iport->signal | w->leftin->signal | w->rightin->signal | TTaskPort(task)->signal);
  521.         }
  522.         
  523.         TTimeQuery(task, &now);
  524.         f = TTIMETOF(&now) - TTIMETOF(&lasttime);
  525.         delayf = 1.0f/WORLDUPDATEPERSECOND - f;
  526.         lasttime = now;
  527.         f *= WORLDUPDATEPERSECOND;
  528.  
  529.         sigballlist(w, &w->activeballs, BALLSIG_DRAW);
  530.  
  531.         mousemove = TFALSE;
  532.  
  533.         if (signals & w->visual->iport->signal)
  534.         {
  535.             while ((imsg = (TIMSG *) TGetMsg(w->visual->iport)))
  536.             {
  537.                 switch (imsg->type)
  538.                 {
  539.                     case TITYPE_VISUAL_NEWSIZE:
  540.                         newsize = TTRUE;
  541.                         break;
  542.                 
  543.                     case TITYPE_VISUAL_CLOSE:
  544.                         abort = TTRUE;
  545.                         break;
  546.     
  547.                     case TITYPE_KEY:
  548.                         if (imsg->code == TKEYCODE_ESC)
  549.                         {
  550.                             abort = TTRUE;
  551.                         }
  552.                         break;
  553.     
  554.                     case TITYPE_MOUSEMOVE:
  555.                         mousex = imsg->mousex;
  556.                         mousey = imsg->mousey;
  557.                         mousemove = TTRUE;
  558.                         break;
  559.     
  560.                     case TITYPE_MOUSEBUTTON:
  561.                         switch (imsg->code)
  562.                         {
  563.                             case TMBCODE_LEFTUP:
  564.                                 if (control)
  565.                                 {
  566.                                     /* lose ball control */
  567.     
  568.                                     setballv(w, control, mousevx, mousevy);
  569.                                     TVSetInput(w->visual, TITYPE_MOUSEMOVE, TITYPE_NONE);
  570.                                     control = TNULL;        
  571.                                 }
  572.                                 break;
  573.     
  574.                             case TMBCODE_LEFTDOWN:
  575.                             {
  576.                                 if (!control)
  577.                                 {
  578.                                     /* get ball control */
  579.     
  580.                                     struct ball *b = pickball(w, imsg->mousex, imsg->mousey);
  581.                                     if (b)
  582.                                     {
  583.                                         control = b;
  584.                                         b->vx = 0; b->vy = 0; b->gravity = 0;
  585.                                         TVSetInput(w->visual, TITYPE_NONE, TITYPE_MOUSEMOVE);
  586.                                     }
  587.                                 }
  588.                                 break;
  589.                             }
  590.                             
  591.                             case TMBCODE_RIGHTDOWN:
  592.                                 if (control)
  593.                                 {
  594.                                     /* remove ball */
  595.     
  596.                                     TSignal(control->task, BALLSIG_SLEEP);
  597.                                     TRemove((TNODE *) control);
  598.                                     TAddTail(&w->cachedballs, (TNODE *) control);
  599.                                     control = TNULL;
  600.                                     TVSetInput(w->visual, TITYPE_MOUSEMOVE, TITYPE_NONE);
  601.                                 }
  602.                                 else 
  603.                                 {
  604.                                     /* new ball */
  605.                                     
  606.                                     struct ball *b = newball(w, imsg->mousex, imsg->mousey);
  607.                                     if (b)
  608.                                     {
  609.                                         control = b;
  610.                                         TVSetInput(w->visual, TITYPE_NONE, TITYPE_MOUSEMOVE);
  611.                                     }
  612.                                 }
  613.                                 break;
  614.     
  615.                             case TMBCODE_RIGHTUP:
  616.                                 if (control)
  617.                                 {
  618.                                     setballv(w, control, mousevx, mousevy);
  619.                                     TVSetInput(w->visual, TITYPE_MOUSEMOVE, TITYPE_NONE);
  620.                                     control = TNULL;
  621.                                 }
  622.                                 break;
  623.                         }
  624.                         break;
  625.                 }
  626.                 TAckMsg(imsg);
  627.             }
  628.         }
  629.  
  630.         if (newsize)
  631.         {
  632.             newsize = TFALSE;
  633.             TVClear(w->visual, w->pentab[PGREY]);
  634.             TVFRect(w->visual, 0,0,600,400, w->pentab[PBLACK]);
  635.             TVFlush(w->visual);
  636.         }
  637.  
  638.         mousevx = (mousevx + (mousex - omx) * f * MOUSEACCEL) * MOUSEFRICTION;
  639.         mousevy = (mousevy + (mousey - omy) * f * MOUSEACCEL) * MOUSEFRICTION;
  640.         omx = mousex;
  641.         omy = mousey;
  642.         
  643.         if (control && mousemove)
  644.         {
  645.             setballpos(w, control, mousex, mousey);
  646.             TSignal(control->task, BALLSIG_DRAW);
  647.         }
  648.  
  649.         if (signals & w->leftin->signal)
  650.         {
  651.             TVFRect(w->visual, 0,404,40,10, w->pentab[PGREEN]);
  652.             handlenetmsg(w, w->leftin, &w->leftout);
  653.         }
  654.         else
  655.         {
  656.             TVFRect(w->visual, 0,404,40,10, w->pentab[PGREY]);
  657.         }
  658.  
  659.         if (signals & w->rightin->signal)
  660.         {
  661.             TVFRect(w->visual, 560,404,40,10, w->pentab[PGREEN]);
  662.             handlenetmsg(w, w->rightin, &w->rightout);
  663.         }
  664.         else
  665.         {
  666.             TVFRect(w->visual, 560,404,40,10, w->pentab[PGREY]);
  667.         }
  668.  
  669.         if (signals & TTaskPort(task)->signal)
  670.         {
  671.             handlenetreply(w);
  672.         }
  673.  
  674.         TVFlushArea(w->visual, 0,0,620,420);
  675.  
  676.     } while (!abort);
  677.  
  678.     destroyballlist(w, &w->activeballs);
  679.     destroyballlist(w, &w->cachedballs);
  680.  
  681.     for (i = 0; i < NUMPENS; ++i)
  682.     {
  683.         TVFreePen(w->visual, w->pentab[i]);
  684.     }
  685.  
  686.     TDestroy(w->visual);
  687.     TDestroy(&w->lock);
  688.     TDestroy(w->leftout);
  689.     TDestroy(w->rightout);
  690.     TDestroy(w->leftin);
  691.     TDestroy(w->rightin);
  692. }
  693.  
  694.  
  695. TVOID destroyballlist(struct world *w, TLIST *list)
  696. {
  697.     TNODE *nextnode, *node = list->head;
  698.     while ((nextnode = node->succ))
  699.     {
  700.         TRemove(node);
  701.         TDestroy(node);
  702.         node = nextnode;
  703.     }
  704. }
  705.  
  706. TVOID sigballlist(struct world *w, TLIST *list, TUINT sig)
  707. {
  708.     TNODE *nextnode, *node = list->head;
  709.     while ((nextnode = node->succ))
  710.     {
  711.         TSignal(((struct ball *) node)->task, sig);
  712.         node = nextnode;
  713.     }
  714. }
  715.  
  716. struct ball *newball(struct world *w, TINT mousex, TINT mousey)
  717. {
  718.     struct ball *b = (struct ball *) TRemHead(&w->cachedballs);
  719.     if (!b)
  720.     {
  721.         b = createball(w->task, w, w->visual, w->pentab[PBLACK], w->pentab[PBLUE], 0.5f, 0.5f, 0.0f, 0.0f);
  722.     }
  723.     if (b)
  724.     {
  725.         b->vx = 0; b->vy = 0; b->gravity = 0;
  726.         setballpos(w, b, mousex, mousey);
  727.         TAddTail(&w->activeballs, (TNODE *) b);
  728.         TSignal(b->task, BALLSIG_WAKE);
  729.     }
  730.  
  731.     return b;
  732. }
  733.  
  734. struct ball *newnetball(struct world *w, TFLOAT x, TFLOAT y, TFLOAT vx, TFLOAT vy)
  735. {
  736.     struct ball *b = (struct ball *) TRemHead(&w->cachedballs);
  737.     if (!b)
  738.     {
  739.         b = createball(w->task, w, w->visual, w->pentab[PBLACK], w->pentab[PBLUE], x, y, vx, vy);
  740.     }
  741.     if (b)
  742.     {
  743.         TLock(&b->lock);
  744.         b->x = x;
  745.         b->y = y;
  746.         b->vx = vx;
  747.         b->vy = vy;
  748.         b->gravity = BALLGRAV;
  749.         TUnlock(&b->lock);
  750.         TAddTail(&w->activeballs, (TNODE *) b);
  751.         TSignal(b->task, BALLSIG_WAKE);
  752.     }
  753.  
  754.     return b;
  755. }
  756.  
  757. TVOID setballpos(struct world *w, struct ball *b, TINT mousex, TINT mousey)
  758. {
  759.     TINT bw, bh;
  760.  
  761.     TLock(&b->lock);
  762.  
  763.     bw = b->radius * 2 * w->width;
  764.     bh = b->radius * 2 * w->height;
  765.     b->x = (TFLOAT) (mousex/*-bw/2*/) / (TFLOAT) (w->width/* - bw*/);
  766.     b->y = (TFLOAT) (mousey-bh/2) / (TFLOAT) (w->height - bh);
  767.     b->x = TCLAMP(0.0f, b->x, 1.0f);
  768.     b->y = TCLAMP(0.0f, b->y, 1.0f);
  769.     b->gravity = 0.0f;
  770.  
  771.     TUnlock(&b->lock);
  772. }
  773.  
  774. TVOID setballv(struct world *w, struct ball *b, TFLOAT mousevx, TFLOAT mousevy)
  775. {
  776.     TINT bw, bh;
  777.  
  778.     TLock(&b->lock);
  779.  
  780.     bw = b->radius * 2 * w->width;
  781.     bh = b->radius * 2 * w->height;
  782.     b->vx = mousevx / (TFLOAT) (w->width - bw);
  783.     b->vy = mousevy / (TFLOAT) (w->height - bh);
  784.     b->gravity = BALLGRAV;
  785.  
  786.     TUnlock(&b->lock);
  787. }
  788.  
  789. struct ball *pickball(struct world *w, TINT mousex, TINT mousey)
  790. {
  791.     TINT bw, bh, bx, by;
  792.     struct ball *b;
  793.     TNODE *nextnode, *node = w->activeballs.tailpred;
  794.     while ((nextnode = node->pred))
  795.     {
  796.         b = (struct ball *) node;
  797.         TLock(&b->lock);
  798.  
  799.         bw = b->radius * 2 * w->width;
  800.         bh = b->radius * 2 * w->height;
  801.         bx = b->x * (w->width - bw);
  802.         by = b->y * (w->height - bh);
  803.  
  804.         TUnlock(&b->lock);
  805.         
  806.         if (mousex >= bx && mousex < bx+bw && mousey >= by && mousey < by+bh)
  807.         {
  808.             return b;
  809.         }
  810.  
  811.         node = nextnode;
  812.     }
  813.     return TNULL;
  814. }
  815.  
  816. TBOOL handlenetmsg(struct world *w, TPORT *inport, TPORT **outport)
  817. {
  818.     TUINT *msg, type, callbackport;
  819.     TSTRPTR sender;
  820.  
  821.     TLock(&w->lock);
  822.  
  823.     while ((msg = TGetMsg(inport)))
  824.     {
  825.         type = TNTOH32(*(msg + 0));
  826.         switch (type)
  827.         {
  828.             case MSG_WELCOME:
  829.                 if (*outport == TNULL)
  830.                 {
  831.                     callbackport = TNTOH32(*((TUINT *) (msg + 1)));
  832.                     sender = TGetMsgSender(msg);
  833.                     if (sender)
  834.                     {
  835.                         TTAGITEM tags[2];
  836.                         TTIME timeout;
  837.                         TFTOTIME(1.0f, &timeout);
  838.                         tags[0].tag = TSock_ReplyTimeout;
  839.                         tags[0].value = (TTAG) &timeout;
  840.                         tags[1].tag = TTAG_DONE;
  841.                         if ((*outport = TFindSockPort(w->task, sender, callbackport, TNULL)))
  842.                         {
  843.                             TAckMsg(msg);
  844.                             break;
  845.                         }
  846.                     }
  847.                 }
  848.                 TDropMsg(msg);
  849.                 break;
  850.  
  851.             case MSG_MIGRATE:
  852.             {
  853.                 TFLOAT x,y,vx,vy;
  854.                 *(msg + 3) = TNTOH32(*(msg + 3)); x = *((TFLOAT *) (msg + 3));
  855.                 *(msg + 4) = TNTOH32(*(msg + 4)); y = *((TFLOAT *) (msg + 4));
  856.                 *(msg + 5) = TNTOH32(*(msg + 5)); vx = *((TFLOAT *) (msg + 5));
  857.                 *(msg + 6) = TNTOH32(*(msg + 6)); vy = *((TFLOAT *) (msg + 6));
  858.                 if (newnetball(w, x,y,vx,vy))
  859.                 {
  860.                     TAckMsg(msg);
  861.                 }
  862.                 else
  863.                 {
  864.                     TDropMsg(msg);
  865.                 }
  866.                 break;
  867.             }
  868.             
  869.             default:
  870.                 TDropMsg(msg);
  871.         }
  872.     }
  873.  
  874.     TUnlock(&w->lock);
  875.  
  876.     return TTRUE;
  877. }
  878.  
  879. TVOID handlenetreply(struct world *w)
  880. {
  881.     TUINT *msg, type;
  882.     struct ball *b;
  883.  
  884.     TLock(&w->lock);
  885.  
  886.     while ((msg = TGetMsg(TTaskPort(w->task))))
  887.     {
  888.         type = TNTOH32(*(msg + 0));
  889.         switch (type)
  890.         {
  891.             case MSG_MIGRATE:
  892.  
  893.                 b = (struct ball *) *(msg + 1);
  894.                 if (TGetMsgStatus(msg) == TMSG_STATUS_FAILED)
  895.                 {
  896.                     if (msg[2] == LEFT)
  897.                     {
  898.                         TDestroy(w->leftout);
  899.                         w->leftout = TNULL;
  900.                     }
  901.                     else
  902.                     {
  903.                         TDestroy(w->rightout);
  904.                         w->rightout = TNULL;
  905.                     }
  906.                     TSignal(b->task, BALLSIG_WAKE);
  907.                 }
  908.                 else
  909.                 {
  910.                     TSignal(b->task, BALLSIG_SLEEP);
  911.                     TRemove((TNODE *) b);
  912.                     TAddTail(&w->cachedballs, (TNODE *) b);
  913.                 }
  914.                 break;
  915.         }
  916.         TFreeMsg(msg);
  917.     }
  918.  
  919.     TUnlock(&w->lock);
  920. }
  921.  
  922.  
  923.  
  924. /******************************************************************** 
  925. **    main
  926. ********************************************************************/
  927.  
  928. int main(int argc, char **argv)
  929. {
  930.     TSTRPTR host = TNULL;
  931.     TUINT port = 0;
  932.     TINT contact = 0;
  933.  
  934.     if (argc == 4)
  935.     {
  936.         if (!TStrCmp("left", argv[1]))
  937.         {
  938.             host = argv[2];
  939.             port = atoi(argv[3]);
  940.             contact = LEFT;
  941.         }
  942.         if (!TStrCmp("right", argv[1]))
  943.         {
  944.             host = argv[2];
  945.             port = atoi(argv[3]);
  946.             contact = RIGHT;
  947.         }
  948.     }
  949.  
  950.     if (host || argc == 1)
  951.     {
  952.         TAPTR task = TCreateTask(TNULL, TNULL, TNULL);
  953.         if (task)
  954.         {
  955.             struct world *w = createworld(task, contact, host, port);
  956.             if (w)
  957.             {
  958.                 printf("\nportnumber-left:  %d\n", w->leftport);
  959.                 printf("portnumber-right: %d\n\n", w->rightport);
  960.                 printf("right mousebutton to create/destroy a ball.\n");
  961.                 printf("to connect to another instance via network:\n\n");
  962.                 printf("%s left <host-IP> <portnumber-right> - connect to the right window border\n", argv[0]);
  963.                 printf("%s right <host-IP> <portnumber-left> - connect to the left window border\n", argv[0]);
  964.                 fflush(NULL);
  965.                 TDestroy(w);
  966.             }
  967.             
  968.             TDestroy(task);
  969.         }
  970.     }
  971.  
  972.     return 0;
  973. }
  974.